﻿using System;
using System.ComponentModel;
using System.Management;
using System.Runtime.Serialization;

namespace GDFlacTools.Controls.CDNotify
{
    public partial class CdNotify : Component
    {
        public delegate void CdMediaChangedEventHandler(object sender, CdNotifyEventArgs args);
        public event CdMediaChangedEventHandler CdMediaChanged;
        private readonly ManagementEventWatcher _managementEventWatcher;

        public CdNotify()
        {
            InitializeComponent();
        }

        public void Start()
        {
            _managementEventWatcher.Start();
        }

        public void Stop()
        {
            _managementEventWatcher.Stop();
        }

        public void OnCdMediaChanged(object sender, CdNotifyEventArgs e)
        {
            if (CdMediaChanged != null)
            {
                CdMediaChanged(this, e);
            }
        }

        private void CdrEventArrived(object sender, EventArrivedEventArgs e)
        {
            // Get the Event object and display it
            var pd = e.NewEvent.Properties["TargetInstance"];
            var mbo = pd.Value as ManagementBaseObject;

            if (mbo != null)
            {
                CdNotifyEventArgs args = mbo.Properties["VolumeName"].Value != null ? new CdNotifyEventArgs(true) : new CdNotifyEventArgs(false);

                OnCdMediaChanged(sender, args);
            }
        }

        public CdNotify(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            var observer = new ManagementOperationObserver();

            // Bind to local machine
            var opt = new ConnectionOptions { EnablePrivileges = true };
            var scope = new ManagementScope("root\\CIMV2", opt);

            try
            {
                var wqlEventQuery = new WqlEventQuery
                    {
                        EventClassName = "__InstanceModificationEvent",
                        WithinInterval = new TimeSpan(0, 0, 1),
                        Condition = @"TargetInstance ISA 'Win32_LogicalDisk' and TargetInstance.DriveType = 5"
                    };

                // DriveType - 5: CDROM
                _managementEventWatcher = new ManagementEventWatcher(scope, wqlEventQuery);

                // register async. event handler
                _managementEventWatcher.EventArrived += CdrEventArrived;
            }
            catch (Exception e)
            {
                throw new CdNotifyException(e.Message, e.InnerException);
            }
        }
    }

    public class CdNotifyEventArgs : EventArgs
    {
        public CdNotifyEventArgs(bool inserted)
        {
            IsInserted = inserted;
        }

        public bool IsInserted { get; set; }
    }

    [Serializable]
    public class CdNotifyException : Exception
    {
        public CdNotifyException()
        { }

        public CdNotifyException(string message)
            : base(message) { }

        public CdNotifyException(string format, params object[] args)
            : base(string.Format(format, args)) { }

        public CdNotifyException(string message, Exception innerException)
            : base(message, innerException) { }

        public CdNotifyException(string format, Exception innerException, params object[] args)
            : base(string.Format(format, args), innerException) { }

        protected CdNotifyException(SerializationInfo info, StreamingContext context)
            : base(info, context) { }
    }
}
